<template>
    <div :style="style">
        <slot></slot>
    </div>
</template>
<script setup lang="ts" name="Grid">
import type { BreakPoint } from "./interface/index";
import { VNodeArrayChildren } from "vue";

type Props = {
    cols?: number | Record<BreakPoint, number>;
    collapsed?: boolean;
    collapsedRows?: number;
    gap?: [number, number] | number;
};

const {
    cols = { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 },
    collapsed = false,
    collapsedRows = 1,
    gap = 0,
} = defineProps<Props>();

// const props = withDefaults(defineProps<Props>(), {
//     cols: () => ({ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }),
//     collapsed: false,
//     collapsedRows: 1,
//     gap: 0,
// });

// 注入 gap 间距
provide("gap", Array.isArray(gap) ? gap[0] : gap);

// 注入响应式断点
let breakPoint = ref<BreakPoint>("xl");
provide("breakPoint", breakPoint);

// 注入要开始折叠的 index
const hiddenIndex = ref(-1);
provide("shouldHiddenIndex", hiddenIndex);

// 注入 cols
const gridCols = computed(() => {
    if (typeof cols === "object") return cols[breakPoint.value] ?? cols;
    return cols;
});
provide("cols", gridCols);

// 寻找需要开始折叠的字段 index
const slots = useSlots().default!();

// 设置间距
const gridGap = computed(() => {
    if (typeof gap === "number") return `${gap}px`;
    if (Array.isArray(gap)) return `${gap[1]}px ${gap[0]}px`;
    return "unset";
});

// 设置style
const style = computed(() => {
    return {
        display: "grid",
        gridGap: gridGap.value,
        gridTemplateColumns: `repeat(${gridCols.value}, minmax(0, 1fr))`,
    };
});

// 寻找需要开始折叠的字段 index
const findIndex = () => {
    let fields: VNodeArrayChildren = [];
    let suffix: VNode | null = null;
    slots.forEach((slot: any) => {
        // suffix
        if (
            typeof slot.type === "object" &&
            slot.type.name === "GridItem" &&
            slot.props?.suffix !== undefined
        )
            suffix = slot;
        // slot children
        if (typeof slot.type === "symbol" && Array.isArray(slot.children))
            fields.push(...slot.children);
    });
    // 计算 suffix 所占用的列
    let suffixCols = 0;
    if (suffix) {
        suffixCols =
            ((suffix as VNode).props![breakPoint.value]?.span ??
                (suffix as VNode).props?.span ??
                1) +
            ((suffix as VNode).props![breakPoint.value]?.offset ??
                (suffix as VNode)!.props?.offset ??
                0);
    }

    try {
        let find = false;
        fields.reduce((prev = 0, current, index) => {
            prev +=
                ((current as VNode)!.props![breakPoint.value]?.span ??
                    (current as VNode)!.props?.span ??
                    1) +
                ((current as VNode)!.props![breakPoint.value]?.offset ??
                    (current as VNode)!.props?.offset ??
                    0);
            if (Number(prev) > collapsedRows * gridCols.value - suffixCols) {
                hiddenIndex.value = index;
                find = true;
                throw "findIndex";
            }
            return prev;
        }, 0);
        if (!find) hiddenIndex.value = -1;
    } catch (e) {
        console.warn(e);
    }
};

// 监听屏幕变化
const resize = (e: UIEvent) => {
    let width = (e.target as Window).innerWidth;
    switch (!!width) {
        case width < 768:
            breakPoint.value = "xs";
            break;
        case width >= 768 && width < 992:
            breakPoint.value = "sm";
            break;
        case width >= 992 && width < 1200:
            breakPoint.value = "md";
            break;
        case width >= 1200 && width < 1920:
            breakPoint.value = "lg";
            break;
        case width >= 1920:
            breakPoint.value = "xl";
            break;
    }
};

// 断点变化时执行 findIndex
watch(
    () => breakPoint.value,
    () => {
        if (collapsed) findIndex();
    }
);

// 监听 collapsed
watch(
    () => collapsed,
    (value) => {
        if (value) return findIndex();
        hiddenIndex.value = -1;
    }
);

onBeforeMount(() => collapsed && findIndex());
onMounted(() => {
    resize({ target: { innerWidth: window.innerWidth } } as unknown as UIEvent);
    window.addEventListener("resize", resize);
});
onActivated(() => {
    resize({ target: { innerWidth: window.innerWidth } } as unknown as UIEvent);
    window.addEventListener("resize", resize);
});
onUnmounted(() => {
    window.removeEventListener("resize", resize);
});
onDeactivated(() => {
    window.removeEventListener("resize", resize);
});

// 暴露 breakPoint
defineExpose({ breakPoint });
</script>
